package com.example.compents.iec.iec104.core;



import com.example.compents.iec.iec104.common.BasicInstruction104;
import com.example.compents.iec.iec104.enums.QualifiersEnum;
import com.example.compents.iec.iec104.enums.TypeIdentifierEnum;
import com.example.compents.iec.iec104.message.MessageDetail;
import com.example.compents.iec.iec104.message.MessageInfo;
import com.example.compents.iec.util.ByteUtil;
import com.example.compents.iec.util.Iec104Util;
import com.sun.corba.se.impl.encoding.CodeSetConversion;

import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;


/**
 * 
* @ClassName: Decoder104
* @Description: 104 协议转码工具 
* @author YDL 
* @date  
 */
public class Decoder104 {

	/**
	 * 将bytes 转换成指定的数据结构
	 * @param bytes
	 * @return
	 */
	public static MessageDetail encoder(byte[] bytes) {
		MessageDetail ruleDetail104 = new MessageDetail();
		int index = 0;
		ruleDetail104.setStart(bytes[index++]);
		ruleDetail104.setApuuLength(bytes[index++] & 0xFF);
		ruleDetail104.setControl(ByteUtil.getByte(bytes, index, 4));
		index += 4;
		if (ruleDetail104.getApuuLength() <= 4) {
			ruleDetail104.setMessages(new ArrayList<>());
			// 如果只有APCI 就此返回
			return ruleDetail104;
		} 
		// 下面是返回ASDU的结构
		ruleDetail104.setTypeIdentifier(TypeIdentifierEnum.getTypeIdentifierEnum(bytes[index++]));
		// 添加可变结构限定词
		Iec104Util.setChanged(ruleDetail104, bytes[index++]);
		ruleDetail104.setTransferReason(ByteUtil.byteArrayToShort(ByteUtil.getByte(bytes, index, 2)));
		index += 2;
		// 
		ruleDetail104.setTerminalAddress(Iec104Util.getTerminalAddressShort(ByteUtil.getByte(bytes, index, 2)));
		index += 2;
		//地址
		ruleDetail104.setMessageAddress(Iec104Util.messageAddressToInt(ByteUtil.getByte(bytes, index,3)));

		Iec104Util.setMeaageAttribute(ruleDetail104);
		setMessage(ruleDetail104, bytes, index);
		return ruleDetail104;
	}

	/**
	 * 
	* @Title: setMessage  
	* @Description: 对消息进行编码  
	* @param @param ruleDetail104
	* @param @param bytes
	* @param @param index 
	* @return void   
	* @throws
	 */
	public static void setMessage(MessageDetail ruleDetail104, byte[] bytes, int index) {
		int mesageIndex = index;
		if (ruleDetail104.isContinuous()) {
			setContinuoustMessage(ruleDetail104, bytes, mesageIndex);
		}  else {
			setNoContinuoustMessage(ruleDetail104, bytes, mesageIndex);
		}
	} 
	
	
	/**
	 * 
	* @Title: setContinuoustMessage  
	* @Description: 设置连续地址的消息 
	* @param ruleDetail104
	* @param bytes
	* @param index 
	* @return void   
	* @throws
	 */
	public static void setContinuoustMessage(MessageDetail ruleDetail104, byte[] bytes, int index) {
		List<MessageInfo> messages = new ArrayList<>();
		int mesageIndex = index;
		// 连续的 前三个字节是地址 
		// 如果是地址连续的只需要设置一个初始地址就可以了
		// TODO 此处不处理地址
		int messageAddress = Iec104Util.messageAddressToInt(ByteUtil.getByte(bytes, mesageIndex, 3));
		ruleDetail104.setMessageAddress(messageAddress);
		mesageIndex += 3;
		if (ruleDetail104.isMessage()) {
			// 获取每个消息的长度
			int messageLength = getMessageLength(ruleDetail104);
			int messageSize = 0;
			while (messageSize < ruleDetail104.getMeasgLength()) {
				MessageInfo messageObj = new MessageInfo();
				messageObj.setMessageAddress(messageAddress);
				byte[] messageInfos = ByteUtil.getByte(bytes, mesageIndex, messageLength);
				mesageIndex += messageLength;
				messageObj.setMessageInfos(messageInfos);
				//对数据的值进行解析
				setMessageValue(ruleDetail104, messageObj);

				if (ruleDetail104.isQualifiers() && TypeIdentifierEnum.isTelemetry(ruleDetail104.getTypeIdentifier())) {
					// 判断是否有限定词
					// 0（每个信息元素后缀1个字节）
					ruleDetail104.setQualifiersType(QualifiersEnum.getQualifiersEnum(ruleDetail104.getTypeIdentifier(), bytes[mesageIndex++]));
				}

				messageSize++;
				messageAddress++;
				messages.add(messageObj);
			}
		}


		if (ruleDetail104.isQualifiers() &&  !TypeIdentifierEnum.isTelemetry(ruleDetail104.getTypeIdentifier())) {
			// 判断是否有限定词
			ruleDetail104.setQualifiersType(QualifiersEnum.getQualifiersEnum(ruleDetail104.getTypeIdentifier(), bytes[mesageIndex++]));
		}


		if (ruleDetail104.isTimeScaleExit()) {
			ruleDetail104.setTimeScale(ByteUtil.byte2Hdate(ByteUtil.getByte(bytes, mesageIndex, 7)));
		}
		ruleDetail104.setMessages(messages);
	} 
	
	
	/**
	 * 
	* @Title: setNoContinuoustMessage  
	* @Description: 设置不连续地址的消息 
	* @param ruleDetail104
	* @param bytes
	* @param index 
	* @return void   
	* @throws
	 */
	public static void setNoContinuoustMessage(MessageDetail ruleDetail104, byte[] bytes, int index) {
		List<MessageInfo> messages = new ArrayList<>();
		int mesageIndex = index;
		// 获取每个消息的长度
		int messageLength = getMessageLength(ruleDetail104);
		int messageSize = 0;
		while (messageSize < ruleDetail104.getMeasgLength()) {
			MessageInfo messageObj = new MessageInfo();
			// 消息地址
			messageObj.setMessageAddress(Iec104Util.messageAddressToInt(ByteUtil.getByte(bytes, mesageIndex, 3)));
			mesageIndex += 3;
			
			if (ruleDetail104.isMessage()) {
				// 消息集合
				byte[] messageInfos = ByteUtil.getByte(bytes, mesageIndex, messageLength);
				mesageIndex += messageLength;
				messageObj.setMessageInfos(messageInfos);

				//对数据的值进行解析
				setMessageValue(ruleDetail104, messageObj);
			} else {
				messageObj.setMessageInfos(new byte[] {});
			}

			if (ruleDetail104.isQualifiers() &&  TypeIdentifierEnum.isTelemetry(ruleDetail104.getTypeIdentifier())) {
				// 判断是否有限定词
				// 0（每个信息元素后缀1个字节）
				ruleDetail104.setQualifiersType(QualifiersEnum.getQualifiersEnum(ruleDetail104.getTypeIdentifier(), bytes[mesageIndex++]));
			}

			messageSize++;
			messages.add(messageObj);
		}


		if (ruleDetail104.isQualifiers() && !TypeIdentifierEnum.isTelemetry(ruleDetail104.getTypeIdentifier())) {
			// 判断是否有限定词
			ruleDetail104.setQualifiersType(QualifiersEnum.getQualifiersEnum(ruleDetail104.getTypeIdentifier(), bytes[mesageIndex++]));
		}


		if (ruleDetail104.isTimeScaleExit()) {
			ruleDetail104.setTimeScale(ByteUtil.byte2Hdate(ByteUtil.getByte(bytes, mesageIndex, 7)));
		}

		ruleDetail104.setMessages(messages);
	}

	/**
	 * 根据类型对数据的值进行解析
	 * */
	private static void setMessageValue(MessageDetail ruleDetail104, MessageInfo messageObj) {
		byte[] bytes = messageObj.getMessageInfos();
		switch (ruleDetail104.getTypeIdentifier().getValue()) {
			case 0x01:
				//不带时标单点遥信
				int binaryData = bytes[0] & 0xFF;
				boolean isValid = ((binaryData >> 7) & 0x01) == 0;
				boolean isCurrentValue = ((binaryData >> 6) & 0x01) == 0;
				boolean isReplaced = ((binaryData >> 5) & 0x01) == 1;
				boolean isLocked = ((binaryData >> 4) & 0x01) == 1;
				boolean isCombined = (binaryData & 0x01) == 1;
				System.out.printf("%s %s %s %s %s ", isCombined ? "合" : "分", isLocked ? "被闭锁" : "未被闭锁", isReplaced ? "被取代" : "未被取代", isCurrentValue ? "当前值" : "非当前值", isValid ? "有效" : "无效"+"/n");
				System.out.println("信息体地址："+messageObj.getMessageAddress());
				break;
			case 0x03:
				//不带时标双点遥信
				int binaryData02 = bytes[0] & 0xFF;
				boolean isValid02 = ((binaryData02 >> 7) & 0x01) == 0;
				boolean isCurrentValue02 = ((binaryData02 >> 6) & 0x01) == 0;
				boolean isReplaced02 = ((binaryData02 >> 5) & 0x01) == 1;
				boolean isLocked02 = ((binaryData02 >> 4) & 0x01) == 1;
				int isCombinedNum = (binaryData02 & 0x03);
				System.out.printf("%s %s %s %s %s ", isCombinedNum==2 ? "合" : "分", isLocked02 ? "被闭锁" : "未被闭锁", isReplaced02 ? "被取代" : "未被取代", isCurrentValue02 ? "当前值" : "非当前值", isValid02 ? "有效" : "无效"+"/n");
				System.out.println("信息体地址："+messageObj.getMessageAddress());
				break;
			case 0x09:
				// 遥测 测量值 归一化值 遥测
				short mv = ByteUtil.byteArrayToShort(bytes);
				System.out.println("messageValue:" + mv);
				break;
			case 0x0B:
				// 遥测 测量值  标度化值 遥测
				break;
			case 0x0D:
				//遥测 短浮点数值
				for (int i = 0; i < bytes.length / 2; i++) {
					byte temp = bytes[i];
					bytes[i] = bytes[bytes.length - 1 - i];
					bytes[bytes.length - 1 - i] = temp;
				}
				ByteBuffer buffer = ByteBuffer.wrap(bytes);
				float messageValue = buffer.getFloat();
				System.out.println("messageValue:" + messageValue);
				break;
			case 0x30:
				// 预置单个参数命令
				break;
			case 0x66:
				// 读单个参数
				break;
			case (byte) 0x84:
				//  读多个参数
				break;
			case (byte) 0x88:
				// 预置多个个参数
				break;
			default:
		}
	}


	/**
	 * 根据类型标识返回消息长度
	 */
	private static int getMessageLength(MessageDetail ruleDetail104) {
		//return ruleDetail104.getTypeIdentifier().getMessageLength();
		int messageLength = 0;
		switch (ruleDetail104.getTypeIdentifier().getValue()) {
			case 0x01:
				// 单点遥信
				messageLength = 1;
				break;
			case 0x03:
				//双点遥信
				messageLength = 1;
			case 0x09:
				// 遥测 测量值 归一化值 遥测
				messageLength = 2;
				break;
			case 0x0B:
				// 遥测 测量值  标度化值 遥测
				messageLength = 2;
				break;
			case 0x0D:
				// 测量值 短浮点数 遥测
				messageLength = 4;
				break;
			case 0x0F:
				// 测量值 短浮点数 遥脉
				messageLength = 4;
				break;
			case 0x30:
				// 预置单个参数命令
				messageLength = 4;
				break;
			case 0x32:
				//短浮点遥调
				messageLength = 4;
				break;
			case 0x66:
				// 读单个参数
				messageLength = 4;
				break;
			case (byte) 0x84:
				//  读多个参数
				messageLength = 4;
				break;
			case (byte) 0x88:
				// 预置多个个参数
				messageLength = 4;
				break;
			case (byte) 0xCE:
				// 预置多个个参数
				messageLength = 4;
				break;
			default:
				messageLength = 0;
		}
		return messageLength;
	}
}
